package com.studerb.service;

import org.hibernate.*;
import org.hibernate.cfg.*;
import com.studerb.exceptions.ServiceException;

/**
 * HibernateUtil taken from Hibernate In Action (2005, Manning)
 * basic methods that are thread safe for obtaining and closing
 * hibernate sessions/transactions
 *
 */
public class HibernateService extends ServiceImp {
	private static SessionFactory sessionFactory;
	private static final ThreadLocal<Session> threadSession = new ThreadLocal<Session>();
	private static final ThreadLocal <Transaction> threadTransaction = new ThreadLocal<Transaction>();
	
	public HibernateService(){}

	public synchronized void start() {
		try {
			super.start();
			sessionFactory = new AnnotationConfiguration().configure("hibernate.cfg.xml").buildSessionFactory();
		} catch (Exception e) {
			started = false;
			throw new ServiceException(e.getMessage(), e);
		}
	}

	public synchronized void stop() {
		super.stop();
	}

	public Session getSession() {
		Session s = threadSession.get();
//		Open a new Session, if this thread has none yet
		if (s == null) {
			s = sessionFactory.openSession();
			threadSession.set(s);
		}
		return s;
	}


	public void closeSession() {
		Session s = threadSession.get();
		threadSession.set(null);
		if (s != null && s.isOpen()){
			s.close();
		}
	}

	public void beginTransaction() {
		Transaction tx =  threadTransaction.get();
		if (tx == null) {
			tx = getSession().beginTransaction();
			threadTransaction.set(tx);
		}
	}
	
	public void commitTransaction() {
		Transaction tx = threadTransaction.get();
		try {
			if ( tx != null && !tx.wasCommitted()
					&& !tx.wasRolledBack() )
				tx.commit();
			threadTransaction.set(null);
		} catch (HibernateException ex) {
			rollbackTransaction();
		}
	}

	public void rollbackTransaction() throws HibernateException {
		Transaction tx = (Transaction) threadTransaction.get();
		try {
			threadTransaction.set(null);
			if ( tx != null && !tx.wasCommitted()
					&& !tx.wasRolledBack() ) {
				tx.rollback();
			}
		} catch (HibernateException ex) {
			throw ex;
		} finally {
			closeSession();
		}
	}

}